import { ElMessage, ElMessageBox } from "element-plus";
import { useRouter } from 'vue-router';
import api from '@/http/api';
import tool from "@/utils/tool";
import { store } from '@/pinia';
import { useUserStore } from "@/pinia/modules/user";

export default class EventHandler {
  constructor(parent, comp, node) {
    this.parent = parent;
    this.comp = comp;
    this.node = node;
    this.globalParam = {};
    this.childrenMap = {};
    this.router = useRouter();
    this.dialogQueue = [];
    this.initInputParam();
    this.intervalMap = {};

    if (this.parent) {
      this.parent.register(node && node.id || '0', this);
    }
  }

  setNode(node) {
    this.node = node;
    this.register(this.node.id, this);
  }

  getNode() {
    return this.node;
  }

  setNodeId(id) {
    this.node.id = id;
  }

  initInputParam() {
    const inputParamList = this.node?.compData?.inputParamList;
    if (!inputParamList || inputParamList.length === 0) return;

    const data = {};
    const param = this.getGlobalParam();
    inputParamList.forEach(item => {
      if (item.input) {
        data[item.id] = item.value || '';
      } else if (param) {
        data[item.id] = param[item.value] || '';
      }
    });
    this.setInputData(data);
  }

  register(childrenId, eventHandler) {
    if (this.childrenMap[childrenId]) {
      childrenId = tool.uuids();
      eventHandler.setNodeId(childrenId);
    }

    this.childrenMap[childrenId] = eventHandler;
    this.startInterval(childrenId, eventHandler);
  }

  startInterval(childrenId, eventHandler) {
    const node = eventHandler.getNode();
    if (node && node.compData && node.compData.autoload && node.compData.autoInterval > 0) {
      const compFun = eventHandler.getCompFun();
      if (compFun && compFun.loadData) {
        this.intervalMap[node.id] = setInterval(() => {
          compFun.loadData();
        }, node.compData.autoInterval * 1000);
      }
    }
  }

  unregister(childrenId) {
    if (!childrenId) {
      childrenId = this.node.id;
    }

    if (this.parent) {
      this.parent.unregister(childrenId);
      return;
    }

    if (this.intervalMap[childrenId]) {
      clearInterval(this.intervalMap[childrenId]);
    }

    if (this.childrenMap[childrenId]) {
      delete this.childrenMap[childrenId];
    }
  }

  async trigger(eventName, data) {
    if (!this.node.compEventList) return;
    for (const event of this.node.compEventList) {
      if (event.name === eventName) {
        const triggerData = {
          ...data,
          ...this.getCompFun().getData()
        }
        await this.parent.publish(event, triggerData);
      }
    }
  }

  async publish(event, data) {
    if (this.parent) {
      await this.parent.publish(event, data);
    } else {
      await this.triggerEvent(event, data);
    }
  }

  async triggerEvent(event, data) {
    if (!event || !event.actionList || event.actionList.length === 0) return;
    for (const action of event.actionList) {
      await this.triggerAction(action, data);
    }
  }

  async triggerAction(action, actionData) {
    if (action.condition && !this.checkCondition(action.conditionList, actionData)) return;

    switch (action.name) {
      case "切换状态":
        this.changeStatus(action, actionData);
        break;
      case "表单校验":
        await this.formValidate(action, actionData);
        break;
      case "传递参数":
        this.sendParam(action, actionData);
        break;
      case "刷新组件":
        await this.refreshComp(action, actionData);
        break;
      case "调用脚本":
        await this.runScript(action, actionData);
        break;
      case "操作数据":
        this.operateData(action, actionData);
        break;
      case "链接页面":
        this.showLinkPage(action, actionData);
        break;
      case "跳转菜单":
        this.gotoMenu(action, actionData);
        break;
      case "跳转大屏":
        this.gotoDashboard(action, actionData);
        break;
      case "关闭页面":
        this.closePage(action, actionData);
        break;
      case "跳转页面":
        this.gotoPage(action, actionData);
        break;
      case "打开网址":
        this.openWebSite(action, actionData);
        break;
      case "系统登录":
        await this.login(action, actionData);
        break;
      case "退出登录":
        await this.logout();
        break;
    }
  }

  checkCondition(conditionList, actionData) {
    let result = false;
    (tool.groupBy(conditionList, (item) => [item.group || 999]) || []).forEach(conditionList => {
      result = result || this.checkConditionList(conditionList, actionData);
    });
    return result;
  }

  checkConditionList(conditionList, actionData) {
    let result = true;
    (conditionList || []).forEach(condition => {
      const paramValue = this.getParams([{fieldName: condition.condition, name: 'value'}], actionData);
      const testValue = paramValue['value'] || '';

      switch(condition.type) {
        case "包含":
          result = result && (testValue || '').indexOf(condition.value || '') >= 0;
          break;
        case "不包含":
          result = result && (testValue || '').indexOf(condition.value || '') === -1;
          break;
        case "等于":
          result = result && (testValue || '') === (condition.value || '');
          break;
        case "不等于":
          result = result && (testValue || '') !== (condition.value || '');
          break;
        case "大于":
          result = result && parseFloat(testValue || '0') > parseFloat(condition.value || '0');
          break;
        case "大于等于":
          result = result && parseFloat(testValue || '0') >= parseFloat(condition.value || '0');
          break;
        case "小于":
          result = result && parseFloat(testValue || '0') < parseFloat(condition.value || '0');
          break;
        case "小于等于":
          result = result && parseFloat(testValue || '0') <= parseFloat(condition.value || '0');
          break;
      }
    });
    return result;
  }

  changeStatus(action/*, actionData*/) {
    for (const key in (action.styleList || {})) {
      const nodeId = key;
      const styleId = action.styleList[key];
      this.childrenMap[nodeId]?.getCompFun()?.changeStyle(styleId);
    }
  }

  async formValidate(action/*, actionData*/) {
    const validates = (action.formList || []).map(nodeId => {
      const component = this.childrenMap[nodeId]?.getCompFun();
      if (!component || !component.validate) {
        return Promise.resolve(true);
      }

      return new Promise((innerResolve, innerReject) => {
        component.validate(valid => {
          if (!valid) {
            innerReject();
          } else {
            innerResolve();
          }
        }).catch(() => innerReject());
      });
    });

    await Promise.all(validates);
  }

  sendParam(action, actionData) {
    for (const key in (action.paramList || {})) {
      const nodeId = key;
      const paramList = action.paramList[key];
      let data = {};
      for (let param of paramList) {
        if (param.empty) {
          data[param.id] = '';
          continue;
        }

        if (param.input) {
          data[param.id] = param.fieldName || '';
        } else {
          if (!param.fieldName || param.fieldName.indexOf(".") < 0) continue;

          const params = param.fieldName.split(".");
          if (params.length >= 2 && params[1] === 'col') {
            data[param.id] = (actionData || {}).col || '';
          } else if (params.length >= 4 && params[1] === 'row') {
            data[param.id] = ((actionData || {}).row || {})[params[3]] || '';
          } else if (params.length === 3 && params[0] === 'event' && params[1] === 'data') {
            data[param.id] = actionData[params[2]] || '';
            if (!data[param.id] && params[2] === '内容') {
              data[param.id] = actionData['value'] || '';
            }
          } else if (params[0] === 'inputParam') {
            data[param.id] = actionData[params[0]][params[1]];
          } else if (params.length > 2 && this.childrenMap[params[0]]) {
            const nodeData = this.childrenMap[params[0]].getCompData();
            data[param.id] = (nodeData[params[1]] ? nodeData[params[1]][params[2]] : '') || '';
          } else if (this.childrenMap[params[0]]) {
            const nodeData = this.childrenMap[params[0]].getCompData();
            data[param.id] = nodeData[params[1]] || '';
          }
        }
      }
      this.checkAndSetInputData(nodeId, data, 0);
    }
  }

  async refreshComp(action/*, actionData*/) {
    for (const nodeId of (action.refreshList || [])) {
      await this.childrenMap[nodeId]?.getCompFun()?.refresh();
    }
  }

  async runScript(action, actionData) {
    if (!action.scriptId) {
      ElMessage.error('未配置执行脚本！');
      return;
    }

    if (action.confirm) {
      let result = await ElMessageBox.confirm(
          action.confirmContent || '',
          action.confirmTitle || "提示",
          { type: "warning" }).catch(() => {}
      );
      if (result !== 'confirm') {
        return;
      }
    }

    let res = await api.runScript(action.scriptId, this.getParams(action.paramList, actionData));
    if (res.code === '1') {
      ElMessage.success(res.message || '执行成功！');
    }
  }

  operateData(/*prop, actionData*/) {

  }

  gotoMenu(action, actionData) {
    if (!action.gotoMenuId) return;
    const query = this.getParams(action.paramList, actionData) || {};
    if (action.gotoType === '本页跳转') {
      this.router.push({name: action.gotoMenuId, query: query})
          .catch(e => console.log("页面跳转失败：", e));
    } else if (action.gotoType === '新页面') {
      const route = this.router.resolve({name: action.gotoMenuId, query: query});
      window.open(route.href, '_blank');
    }
  }

  gotoDashboard(action, actionData) {
    if (!action.gotoDashboardId) return;
    const query = this.getParams(action.paramList, actionData) || {};
    if (action.gotoType === '本页跳转') {
      this.router.push({name: 'dashboard', params: {dashboardId: action.gotoDashboardId}, query: query})
          .catch(e => console.log("页面跳转失败：", e));
    } else if (action.gotoType === '新页面') {
      const route = this.router.resolve({name: 'dashboard', params: {dashboardId: action.gotoDashboardId}, query: query});
      window.open(route.href, '_blank');
    }
  }

  showLinkPage(action, actionData) {
    const options = {
      pageId: action.linkPageId,
      showTitle: action.showTitle,
      title: action.title,
      fullscreen: action.fullscreen,
      showWidth: action.showWidth && /^\d+$/.test(action.showWidth) ? (action.showWidth + 'px') : action.showWidth,
      closeOnClickModal: action.closeOnClickModal,
      showFooter: action.showFooter,
      disabled: !action.canEdit,
      dialogEdit: action.canEdit,
      operate: action.canEdit ? '编辑' : '明细',
      options: {
        inputParam: this.getParams(action.paramList, actionData)
      }
    }
    if (action.linkType === '弹窗') {
      this.getCompFun().showDialog(options);
    } else if (action.linkType === '抽屉') {
      this.getCompFun().showDrawer(options);
    }
  }

  closePage(action/*, actionData*/) {
    if (action.closeType === '当前窗口') {
      this.closeDialog();
    } else {
      window.close();
    }
  }

  gotoPage(action, actionData) {
    if (!action.gotoPageId) return;
    const params = this.getParams(action.paramList, actionData);
    this.router.push({path: '/page/' + action.gotoPageId, query: params})
        .catch(e => console.log('跳转出错：' + e));
  }

  openWebSite(action, actionData) {
    if (!action.website) return;

    let website;
    if (action.websiteInput) {
      website = action.website;
    } else {
      const paramValue = this.getParams([{fieldName: action.website, name: 'value'}], actionData);
      website = paramValue['value'] || '';
    }
    window.open(website, '_blank');
  }

  async login(action, actionData) {
    let res = await api.login(this.getParams(action.paramList, actionData));
    if (res.code === '1') {
      const userStore = useUserStore(store);
      userStore.setUser(res.data);
      ElMessage.success(res.message || '登录成功！');
    }
  }

  async logout() {
    let res = await api.logout();
    if (res.code === '1') {
      const userStore = useUserStore(store);
      userStore.clearStorage();
      ElMessage.success(res.message || '退出登录成功！');
    }
  }

  addDialog(option) {
    this.dialogQueue.unshift(option);
  }

  closeDialog(option) {
    if (this.parent) {
      this.parent.closeDialog(option);
    } else {
      const head = this.dialogQueue.shift();
      if (!option) {
        head && (head.visible = false);
      } else if (head && head !== option) {
        head.visible = false;
        this.closeDialog(option);
      }
    }
  }

  getParams(paramList, actionData) {
    const inputParam = {};
    (paramList || []).forEach(param => {
      if (param.input) {
        inputParam[param.name] = param.fieldName || '';
      } else {
        let params = (param.fieldName || '').split(".");
        if (params.length >= 2 && params[1] === 'col') {
          let value = (actionData || {}).col || '';
          if (value) {
            inputParam[param.name ? param.name : param.pageParamId || ''] = value;
          }
        } else if (params.length >= 4 && params[1] === 'row') {
          let value = ((actionData || {}).row || {})[params[3]];
          if (value) {
            inputParam[param.name ? param.name : param.pageParamId || ''] = value;
          }
        } else if (params.length >= 3 && params[1] === 'row') {
          let value = (actionData || {}).row || {};
          if (value) {
            inputParam[param.name ? param.name : param.pageParamId || ''] = value;
          }
        } else if (params.length === 3 && params[0] === 'event' && params[1] === 'data') {
          inputParam[param.name ? param.name : param.pageParamId || ''] = actionData[params[2]] || '';
          if (!inputParam[param.id] && params[2] === '内容') {
            inputParam[param.name ? param.name : param.pageParamId || ''] = actionData['value'] || '';
          }
        } else if (params[0] === 'inputParam') {
          inputParam[param.name] = actionData[params[0]][params[1]];
        } else if (this.childrenMap[params[0]]) {
          let data = this.childrenMap[params[0]]?.getCompData();
          if (params.length > 2) {
            if (data[params[1]] && data[params[1]][params[2]]) {
              inputParam[param.name] = data[params[1]][params[2]];
            }
          } else if (data && data[params[1]]) {
            inputParam[param.name] = data[params[1]];
          }
        }
      }
    });
    return inputParam;
  }

  getCompFun() {
    return this.comp.exposed;
  }

  checkAndSetInputData(nodeId, data, times) {
    if (times >= 10) return;

    if (this.childrenMap[nodeId]) {
      this.childrenMap[nodeId].setInputData(data);
    } else {
      setTimeout(() => this.checkAndSetInputData(nodeId, data, ++times), 100);
    }
  }

  setInputData(data) {
    if (!this.node.inputParam) {
      this.node.inputParam = {};
    }
    Object.assign(this.node.inputParam, data);
  }

  getNodeData(nodeId) {
    if (this.childrenMap && this.childrenMap[nodeId]) {
      return this.childrenMap[nodeId].getCompData();
    } else {
      return this.parent?.getNodeData(nodeId) || {};
    }
  }

  setGlobalParam(globalParam) {
    this.globalParam = globalParam;
  }

  getGlobalParam() {
    if (this.parent) {
      return this.parent.getGlobalParam();
    } else {
      return this.globalParam;
    }
  }

  getCompData() {
    return this.getCompFun().getData ? this.getCompFun().getData() : {};
  }

  destroy() {
    for (const interval in this.intervalMap) {
      if (this.intervalMap[interval]) {
        clearInterval(this.intervalMap[interval]);
      }
    }
  }
}

